#include "DP.h"
double bar;

void printPath(path & myPath){
        cout << "From cell " << myPath.from_cell << ". To cell " 
             << myPath.to_cell << ". With slack " << myPath.slack << endl;
        
        cout << "Contained cells are ";
        for(unsigned int i = 0; i < myPath.instances.size(); i++)
                cout << myPath.instances[i] << " ";
        cout << endl;
        
}


void read_file(ifstream &fin, vector<path> & paths){
        //cout << "bar is " << bar << endl;
        assert(paths.size() == 0);
        string str;
        getline(fin, str);//skip the first line
        while(!fin.eof()){
                getline(fin, str);
                if(str[0] <= 32)//check for empty line
                        continue;
                
                string useless;
                if(str.find("path") != string::npos){
                        path myPath; 
                        
                        getline(fin, str);
                        stringstream ss(str);
                        ss >> useless;
                        ss >> useless;
                        ss >> myPath.from_cell;
                        
                        getline(fin, str);
                        stringstream ss1(str);
                        ss1 >> useless;
                        ss1 >> useless;
                        ss1 >> myPath.to_cell;
                        
                        getline(fin, str);//name
                        getline(fin, str);//cycle
                        getline(fin, str);//slack
                        
                        stringstream ss2(str);
                        ss2 >> useless;
                        //cout << "here " << useless << endl;
                        string tmp_slack;
                        ss2 >> tmp_slack;
                        //cout << "slack " << tmp_slack << endl;
                        myPath.slack = atof(tmp_slack.c_str());
                        myPath.slack += bar;

                        getline(fin, str);//launch
                        getline(fin, str);//transition
                        
                        while(1){
                                getline(fin, str);//gates
                                if(str[2] == '}')
                                        break;
                                
                                unsigned int pos = str.find('"');
                                assert(pos != string::npos);
                                unsigned int beg = pos + 1;
                                pos++;
                                //cout << "hehe " << str << endl;
                                while(str[pos] != '/' && str[pos] != '"')
                                        pos++;
                                string tmp = str.substr(beg, pos - beg);
                                //cout << tmp << endl;
                                myPath.instances.push_back(tmp);
                        }
                        paths.push_back(myPath);
                }
                else
                        continue;
        }
}


int main(int argc, char* argv[]){

        if(argc != 6){
                cout << "Usage: ./DP [benchname] [mode] [set_id] [factor] [bar]" << endl;
                exit(0);
        }
        
        string str = argv[1];
        str.erase(str.begin() + str.find("bench"), str.end());
        str += "rpt_";
        if(str.find("b22") == string::npos){
                str += argv[2];
                str += "_";
        }
        
        str += argv[3];
        str += "_";
        
        string f0 = str + "1";
        //cout << "File 0's name is " << f0 << endl;
        ifstream fin0(f0.c_str());
        if(!fin0.is_open()){
                cout << "Open golden rpt for benchmark "<< argv[1] 
                     << " for set " << argv[3] << "failed!" << endl;
                exit(1);
        }
        
        string f1 = str + "2";
        //cout << "File 1's name is " << f1 << endl;
        ifstream fin1(f1.c_str());
        if(!fin1.is_open()){
                cout << "Open predicted rpt for benchmark "<< argv[1] 
                     << " for set " << argv[3] << "failed!" << endl;
                exit(1);
        }
        
        string f2 = str + "3";
        //cout << "File 2's name is " << f2 << endl;
        ifstream fin2(f2.c_str());
        if(!fin2.is_open()){
                //cout << "Open srr rpt for benchmark "<< argv[1] 
                //<< " for set " << argv[3] << "failed!" << endl;
                cout << "Open BC rpt for benchmark "<< argv[1] 
                     << " for set " << argv[3] << "failed!" << endl;
                exit(1);
        }
        
        string f3 = str + "5";
        //cout << "File 3's name is " << f3 << endl;
        ifstream fin3(f3.c_str());
        if(!fin3.is_open()){
                //cout << "Open alternative rpt for benchmark "<< argv[1] 
                //<< " for set " << argv[3] << "failed!" << endl;
                cout << "Open WC rpt for benchmark "<< argv[1] 
                     << " for set " << argv[3] << "failed!" << endl;
                exit(1);
        }
        
        double cycle_period;
        if(str.find("b22") != string::npos){
                cycle_period = 7.5;
                //bar = 0.45;
        }
        else if(str.find("b18") != string::npos){
                cycle_period = 7.35;
                //bar = 8.9;
        }
        else if(str.find("b17") != string::npos){
                cycle_period = 5.0;
                //bar = 0.0;
        }
        else if(str.find("dsp") != string::npos){
                cycle_period = 18.0;
                //bar = 11.8;
        }
        else if(str.find("DMA") != string::npos){
                cycle_period = 10.7;
                //bar = -0.61;
        }
        else if(str.find("des_perf") != string::npos){
                cycle_period = 11.7;
                //bar = 5.3;
        }
        else{
                cycle_period = 7.02;
                bar = 0.0;
        }
        
        double factor=atof(argv[4]);
        bar = atof(argv[5]);
        cout << "bar is " << bar << endl;
        
        vector<path> paths0;
        read_file(fin0, paths0);
        
        vector<path> paths1;
        read_file(fin1, paths1);

        vector<path> paths2;
        read_file(fin2, paths2);
        
        vector<path> paths3;
        read_file(fin3, paths3);
        
        /*
        cout << "Printing paths0 (golden) infomation..." << endl;
        for(unsigned int i = 0; i < paths0.size(); i++)
                printPath(paths0[i]);
        
        cout << "Printing paths1 (predicted) infomation..." << endl;
        for(unsigned int i = 0; i < paths1.size(); i++)
                printPath(paths1[i]);
        
        cout << "Printing paths2 (alternative) infomation..." << endl;
        for(unsigned int i = 0; i < paths2.size(); i++)
                printPath(paths2[i]);
        
        cout << "Printing paths3 (srr) infomation..." << endl;
        for(unsigned int i = 0; i < paths3.size(); i++)
                printPath(paths3[i]);
        */
        // Extract the critical paths
        
        //cout << endl;
        //cout << "...............NEW ITERATION..............." << endl;
        //cout << endl;
        
        vector<path> paths0_t;
        //cout << "Before Critical Path Extraction, path0's size is " << paths0.size() << endl;
        for(unsigned int i = 0; i < paths0.size(); i++){
                if(fabs(paths0[i].slack) <= factor * (cycle_period + bar))
                        paths0_t.push_back(paths0[i]);
        }
        swap(paths0_t, paths0);
        paths0_t.clear();
        //cout << "After Critical Path Extraction, path0's size is " << paths0.size() << endl;
        
        vector<path> paths1_t;
        //cout << "Before Critical Path Extraction, path1's size is " << paths1.size() << endl;
        for(unsigned int i = 0; i < paths1.size(); i++){
                if(fabs(paths1[i].slack) <= factor * (cycle_period + bar))
                        paths1_t.push_back(paths1[i]);
        }
        swap(paths1_t, paths1);
        paths1_t.clear();
        //cout << "After Critical Path Extraction, path1's size is " << paths1.size() << endl;
        
        vector<path> paths2_t;
        //cout << "Before Critical Path Extraction, path2's size is " << paths2.size() << endl;
        for(unsigned int i = 0; i < paths2.size(); i++){
                if(fabs(paths2[i].slack) <= factor * (cycle_period + bar))
                        //if(paths2[i].slack <= factor * (cycle_period + bar))
                        paths2_t.push_back(paths2[i]);
        }
        swap(paths2_t, paths2);
        paths2_t.clear();
        //cout << "After Critical Path Extraction, path2's size is " << paths2.size() << endl;
        
        vector<path> paths3_t;
        //cout << "Before Critical Path Extraction, path2's size is " << paths2.size() << endl;
        for(unsigned int i = 0; i < paths3.size(); i++){
                if(fabs(paths3[i].slack) <= factor * (cycle_period + bar))
                        //if(paths3[i].slack <= factor * (cycle_period + bar))
                        paths3_t.push_back(paths3[i]);
        }
        swap(paths3_t, paths3);
        paths3_t.clear();
        //cout << "After Critical Path Extraction, path2's size is " << paths2.size() << endl;
        
        int pred_overlap = 0;
        double pred_off = 0.0;
        if(paths1.size() > paths0.size()){
                for(unsigned int i = 0; i < paths0.size(); i++){
                        for(unsigned int j = 0; j < paths1.size(); j++){
                                if(paths1[j] == paths0[i]){
                                        pred_off += fabs((paths1[j].slack - paths0[i].slack) / paths0[i].slack);
                                        pred_overlap++;
                                        break;
                                }
                        }
                }
        }
        else{
                for(unsigned int i = 0; i < paths1.size(); i++){
                        for(unsigned int j = 0; j < paths0.size(); j++){
                                if(paths1[i] == paths0[j]){
                                        pred_off += fabs((paths1[j].slack - paths0[i].slack) / paths0[i].slack);
                                        pred_overlap++;
                                        break;
                                }
                        }
                }
        }
        pred_off /= pred_overlap;
        
        int alt_overlap = 0;
        double alt_off = 0.0;
        if(paths2.size() > paths0.size()){
                for(unsigned int i = 0; i < paths0.size(); i++){
                        for(unsigned int j = 0; j < paths2.size(); j++){
                                if(paths2[j] == paths0[i]){
                                        alt_off += fabs((paths2[j].slack - paths0[i].slack) / paths0[i].slack);
                                        alt_overlap++;
                                        break;
                                }
                        }
                }
        }
        else{
                for(unsigned int i = 0; i < paths2.size(); i++){
                        for(unsigned int j = 0; j < paths0.size(); j++){
                                if(paths2[i] == paths0[j]){
                                        alt_off += fabs((paths2[j].slack - paths0[i].slack) / paths0[i].slack);
                                        alt_overlap++;
                                        break;
                                }
                        }
                }
        }
        alt_off /= alt_overlap;
        
        int srr_overlap = 0;
        double srr_off = 0.0;
        if(paths3.size() > paths0.size()){
                for(unsigned int i = 0; i < paths0.size(); i++){
                        for(unsigned int j = 0; j < paths3.size(); j++){
                                if(paths3[j] == paths0[i]){
                                        srr_off += fabs((paths3[j].slack - paths0[i].slack) / paths0[i].slack);
                                        srr_overlap++;
                                        break;
                                }
                        }
                }
        }
        else{
                for(unsigned int i = 0; i < paths3.size(); i++){
                        for(unsigned int j = 0; j < paths0.size(); j++){
                                if(paths3[i] == paths0[j]){
                                        srr_off += fabs((paths3[j].slack - paths0[i].slack) / paths0[i].slack);
                                        srr_overlap++;
                                        break;
                                }
                        }
                }
        }
        srr_off /= srr_overlap;
        
        cout << "[3] off is " << pred_off << " [2] off is " << alt_off << " [5] off is " << srr_off << endl;
        
        cout << paths0.size() << " ";
        cout << (double)(pred_overlap) / paths0.size() << " ";
        cout << 1.0 - (double)(pred_overlap) / paths0.size() << " ";
        cout << (double)(paths1.size() - pred_overlap) / paths0.size() << " ";
        
        cout << (double)(alt_overlap) / paths0.size() << " ";
        cout << 1.0 - (double)(alt_overlap) / paths0.size() << " ";
        cout << (double)(paths2.size() - alt_overlap) / paths0.size() << " ";
        
        cout << (double)(srr_overlap) / paths0.size() << " ";
        cout << 1.0 - (double)(srr_overlap) / paths0.size() << " ";
        cout << (double)(paths3.size() - srr_overlap) / paths0.size() << " ";
        
        // For failing paths (negative slack)
        // First extract
        
        //cout << "Critical Path number: path0's size is " << paths0.size() << endl;
        for(unsigned int i = 0; i < paths0.size(); i++){
                if(paths0[i].slack <= 0.0)
                        paths0_t.push_back(paths0[i]);
        }
        swap(paths0_t, paths0);
        paths0_t.clear();
        //cout << "Failing Path number: path0's size is " << paths0.size() << endl;
        
        //cout << "Critical Path number: path1's size is " << paths1.size() << endl;
        for(unsigned int i = 0; i < paths1.size(); i++){
                if(paths1[i].slack <= 0.0)
                        paths1_t.push_back(paths1[i]);
        }
        swap(paths1_t, paths1);
        paths1_t.clear();
        //cout << "Failing Path number: path1's size is " << paths1.size() << endl;
        
        //cout << "Critical Path number: path2's size is " << paths2.size() << endl;
        for(unsigned int i = 0; i < paths2.size(); i++){
                if(paths2[i].slack <= 0.0)
                        paths2_t.push_back(paths2[i]);
        }
        swap(paths2_t, paths2);
        paths2_t.clear();
        //cout << "Failing Path number: path2's size is " << paths2.size() << endl;
        
        //cout << "Critical Path number: path2's size is " << paths2.size() << endl;
        for(unsigned int i = 0; i < paths3.size(); i++){
                if(paths3[i].slack <= 0.0)
                        paths3_t.push_back(paths3[i]);
        }
        swap(paths3_t, paths3);
        paths3_t.clear();
        //cout << "Failing Path number: path2's size is " << paths2.size() << endl;
        
        pred_overlap = 0;
        pred_off = 0.0;
        double pred_avg = 0.0;
        if(paths1.size() > paths0.size()){
                for(unsigned int i = 0; i < paths0.size(); i++){
                        pred_avg += fabs(paths1[i].slack);                        
                        for(unsigned int j = 0; j < paths1.size(); j++){
                                if(paths1[j] == paths0[i]){
                                        pred_off += fabs((paths1[j].slack - paths0[i].slack) / paths0[i].slack);
                                        pred_overlap++;
                                        break;
                                }
                        }
                }
        }
        else{
                for(unsigned int i = 0; i < paths1.size(); i++){
                        pred_avg += fabs(paths1[i].slack);                        
                        for(unsigned int j = 0; j < paths0.size(); j++){
                                if(paths1[i] == paths0[j]){
                                        pred_off += fabs((paths1[j].slack - paths0[i].slack) / paths0[i].slack);
                                        pred_overlap++;
                                        break;
                                }
                        }
                }
        }
        
        pred_avg /= paths1.size();
        pred_off /= pred_overlap;
        //cout << "pred_avg is " << pred_avg << endl;

        alt_overlap = 0;
        alt_off = 0.0;
        double alt_avg = 0.0;
        if(paths2.size() > paths0.size()){
                for(unsigned int i = 0; i < paths0.size(); i++){
                        alt_avg += fabs(paths2[i].slack);
                        for(unsigned int j = 0; j < paths2.size(); j++){
                                if(paths2[j] == paths0[i]){
                                        alt_off += fabs((paths2[j].slack - paths0[i].slack) / paths0[i].slack);
                                        alt_overlap++;
                                        break;
                                }
                        }
                }
        }
        else{
                for(unsigned int i = 0; i < paths2.size(); i++){
                        alt_avg += fabs(paths2[i].slack);
                        for(unsigned int j = 0; j < paths0.size(); j++){
                                if(paths2[i] == paths0[j]){
                                        alt_off += fabs((paths2[j].slack - paths0[i].slack) / paths0[i].slack);
                                        alt_overlap++;
                                        break;
                                }
                        }
                }
        }
        
        alt_avg /= paths2.size();
        alt_off /= alt_overlap;
        //cout << "alt_avg is " << alt_avg << endl;
        
        srr_overlap = 0;
        srr_off = 0.0;
        double srr_avg = 0.0;
        if(paths3.size() > paths0.size()){
                for(unsigned int i = 0; i < paths0.size(); i++){
                        srr_avg += fabs(paths3[i].slack);
                        for(unsigned int j = 0; j < paths3.size(); j++){
                                if(paths3[j] == paths0[i]){
                                        srr_off += fabs((paths3[j].slack - paths0[i].slack) / paths0[i].slack);
                                        srr_overlap++;
                                        break;
                                }
                        }
                }
        }
        else{
                for(unsigned int i = 0; i < paths3.size(); i++){
                        srr_avg += fabs(paths3[i].slack);
                        for(unsigned int j = 0; j < paths0.size(); j++){
                                if(paths3[i] == paths0[j]){
                                        srr_off += fabs((paths3[j].slack - paths0[i].slack) / paths0[i].slack);
                                        srr_overlap++;
                                        break;
                                }
                        }
                }
        }
        
        srr_avg /= paths3.size();
        srr_off /= srr_overlap;
        //cout << "srr_avg is " << srr_avg << endl;
        
        double gold_avg = 0.0;
        for(unsigned int j = 0; j < paths0.size(); j++){
                gold_avg += fabs(paths0[j].slack);
        }
        gold_avg /= paths0.size();
        //cout << "gold_avg is " << gold_avg << endl;
        
        //cout << "#cp p1/cp p2/cp fa/cp p1/cp p2/cp fa/cp" << endl;
        cout << paths0.size() << " ";
        cout << (double)(pred_overlap) / paths0.size() << " ";
        cout << 1.0 - (double)(pred_overlap) / paths0.size() << " ";
        cout << (double)(paths1.size() - pred_overlap) / paths0.size() << " ";
        
        cout << (double)(alt_overlap) / paths0.size() << " ";
        cout << 1.0 - (double)(alt_overlap) / paths0.size() << " ";
        cout << (double)(paths2.size() - alt_overlap) / paths0.size() << " ";
        
        cout << (double)(srr_overlap) / paths0.size() << " ";
        cout << 1.0 - (double)(srr_overlap) / paths0.size() << " ";
        cout << (double)(paths3.size() - srr_overlap) / paths0.size() << endl;
        
        cout << "[3] off is " << pred_off << " [2] off is " << alt_off << " [5] off is " << srr_off << endl;
        //cout << "pred_off is " << pred_off << " alt_off is " << alt_off << " srr_off is " << srr_off << endl;
        
        return 0;
}
